package net.media.datafw.database.pool;

import java.sql.Connection;
import java.util.LinkedList;
import java.util.concurrent.Semaphore;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.media.datafw.database.ConnectionManager;
import net.media.datafw.database.DataBaseConnection;
import net.media.datafw.database.model.DataBaseConfiguration;

public class ConnectionPool {
	Logger logger = LoggerFactory.getLogger(getClass());
	private ConnectionManager connectionManager;
	private DataBaseConfiguration configuration;

	private Semaphore freePoolPermit;
	private Semaphore connectionPermit;
	private LinkedList<DataBaseConnection> connectionsInUse;
	private LinkedList<DataBaseConnection> connectionsInFree;

	public ConnectionPool(int maximumConnections, DataBaseConfiguration configuration, ConnectionManager connectionManager) {
		this.connectionPermit = new Semaphore(maximumConnections);
		this.connectionManager = connectionManager;
		this.configuration = configuration;
		this.freePoolPermit = new Semaphore(0);
		this.connectionsInFree = new LinkedList<DataBaseConnection>();
		this.connectionsInUse = new LinkedList<DataBaseConnection>();
	}

	public DataBaseConnection getConnection() {
		DataBaseConnection connection = null;
		try {
			if (freePoolPermit.availablePermits() > 0) {
				connection = getConnectionInFree();
			}
			if (connection == null && connectionPermit.availablePermits() > 0) {
				synchronized (this) {
					connectionPermit.acquire();
					Connection cxn = connectionManager.createConnection(configuration);
					connection = new DataBaseConnection(cxn, connectionManager, this);
					connectionsInUse.add(connection);
				}
			}
		} catch (InterruptedException ie) {
			logger.error(" Error in getting Connection Permit", ie);
		}
		return connection;
	}

	private DataBaseConnection getConnectionInFree() {
		DataBaseConnection connection = null;
		try {
			synchronized (this) {
				connection = connectionsInFree.remove(freePoolPermit.availablePermits() - 1);
				freePoolPermit.acquire();
				connectionsInUse.add(connection);
			}
		} catch (InterruptedException ie) {
			logger.error(" Error in getting free Connection Permit", ie);
		}
		return connection;
	}

	public void putBack(DataBaseConnection connection) {
		if (connection != null) {
			synchronized (this) {
				connectionsInUse.remove(connection);
				if (!connection.isMarkedForClose()) {
					freePoolPermit.release();
					connectionsInFree.add(connection);
					connection = null;
				}
				if (connection != null) {
					connectionPermit.release();
					connectionManager.closeConnection(connection);
				}
			}
		}
	}

	public DataBaseConfiguration getConfigeration() {
		return configuration;
	}
}
